home *** CD-ROM | disk | FTP | other *** search
/ ShareWare OnLine 2 / ShareWare OnLine Volume 2 (CMS Software)(1993).iso / os2 / elvis172.zip / move1.c < prev    next >
C/C++ Source or Header  |  1993-01-06  |  11KB  |  619 lines

  1. /* move1.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    14407 SW Teal Blvd. #C
  6.  *    Beaverton, OR 97005
  7.  *    kirkenda@cs.pdx.edu
  8.  */
  9.  
  10.  
  11. /* This file contains most movement functions */
  12.  
  13. #include "config.h"
  14. #include "vi.h"
  15. #include "ctype.h"
  16.  
  17. MARK    m_updnto(m, cnt, cmd)
  18.     MARK    m;    /* movement is relative to this mark */
  19.     long    cnt;    /* a numeric argument */
  20.     int    cmd;    /* the command character */
  21. {
  22.     DEFAULT(cmd == 'G' ? nlines : 1L);
  23.  
  24.     /* move up or down 'cnt' lines */
  25.     switch (cmd)
  26.     {
  27.       case ctrl('P'):
  28.       case '-':
  29.       case 'k':
  30.         m -= MARK_AT_LINE(cnt);
  31.         break;
  32.  
  33.       case 'G':
  34.         if (cnt < 1L || cnt > nlines)
  35.         {
  36.             msg("Only %ld lines", nlines);
  37.             return MARK_UNSET;
  38.         }
  39.         m = MARK_AT_LINE(cnt);
  40.         break;
  41.  
  42.       case '_':
  43.         cnt--;
  44.         /* fall through... */
  45.  
  46.       default:
  47.         m += MARK_AT_LINE(cnt);
  48.     }
  49.  
  50.     /* if that left us screwed up, then fail */
  51.     if (m < MARK_FIRST || markline(m) > nlines)
  52.     {
  53.         return MARK_UNSET;
  54.     }
  55.  
  56.     return m;
  57. }
  58.  
  59. /*ARGSUSED*/
  60. MARK    m_right(m, cnt, key, prevkey)
  61.     MARK    m;    /* movement is relative to this mark */
  62.     long    cnt;    /* a numeric argument */
  63.     int    key;    /* movement keystroke */
  64.     int    prevkey;/* operator keystroke, or 0 if none */
  65. {
  66.     int        idx;    /* index of the new cursor position */
  67.  
  68.     DEFAULT(1);
  69.  
  70.     /* If used with an operator, then move 1 less character, since the 'l'
  71.      * command includes the character that it moves onto.
  72.      */
  73.     if (prevkey != '\0')
  74.     {
  75.         cnt--;
  76.     }
  77.  
  78.     /* move to right, if that's OK */
  79.     pfetch(markline(m));
  80.     idx = markidx(m) + cnt;
  81.     if (idx < plen)
  82.     {
  83.         m += cnt;
  84.     }
  85.     else
  86.     {
  87.         return MARK_UNSET;
  88.     }
  89.  
  90.     return m;
  91. }
  92.  
  93. /*ARGSUSED*/
  94. MARK    m_left(m, cnt)
  95.     MARK    m;    /* movement is relative to this mark */
  96.     long    cnt;    /* a numeric argument */
  97. {
  98.     DEFAULT(1);
  99.  
  100.     /* move to the left, if that's OK */
  101.     if (markidx(m) >= cnt)
  102.     {
  103.         m -= cnt;
  104.     }
  105.     else
  106.     {
  107.         return MARK_UNSET;
  108.     }
  109.  
  110.     return m;
  111. }
  112.  
  113. /*ARGSUSED*/
  114. MARK    m_tocol(m, cnt, cmd)
  115.     MARK    m;    /* movement is relative to this mark */
  116.     long    cnt;    /* a numeric argument */
  117.     int    cmd;    /* either ctrl('X') or '|' */
  118. {
  119.     char    *text;    /* text of the line */
  120.     int    col;    /* column number */
  121.     int    idx;    /* index into the line */
  122.  
  123.  
  124.     /* if doing ^X, then adjust for sideways scrolling */
  125.     if (cmd == ctrl('X'))
  126.     {
  127.         DEFAULT(*o_columns & 0xff);
  128.         cnt += leftcol;
  129.     }
  130.     else
  131.     {
  132.         DEFAULT(1);
  133.     }
  134.  
  135.     /* internally, columns are numbered 0..COLS-1, not 1..COLS */
  136.     cnt--;
  137.  
  138.     /* if 0, that's easy */
  139.     if (cnt == 0)
  140.     {
  141.         m &= ~(BLKSIZE - 1);
  142.         return m;
  143.     }
  144.  
  145.     /* find that column within the line */
  146.     pfetch(markline(m));
  147.     text = ptext;
  148.     for (col = idx = 0; col < cnt && *text; text++, idx++)
  149.     {
  150.         if (*text == '\t' && !*o_list)
  151.         {
  152.             col += *o_tabstop;
  153.             col -= col % *o_tabstop;
  154.         }
  155.         else if (UCHAR(*text) < ' ' || *text == '\177')
  156.         {
  157.             col += 2;
  158.         }
  159. #ifndef NO_CHARATTR
  160.         else if (text[0] == '\\' && text[1] == 'f' && text[2] && *o_charattr)
  161.         {
  162.             text += 2; /* plus one more as part of for loop */
  163.         }
  164. #endif
  165.         else
  166.         {
  167.             col++;
  168.         }
  169.     }
  170.     if (!*text)
  171.     {
  172.         /* the desired column was past the end of the line, so
  173.          * act like the user pressed "$" instead.
  174.          */
  175.         return m | (BLKSIZE - 1);
  176.     }
  177.     else
  178.     {
  179.         m = (m & ~(BLKSIZE - 1)) + idx;
  180.     }
  181.     return m;
  182. }
  183.  
  184. /*ARGSUSED*/
  185. MARK    m_front(m, cnt)
  186.     MARK    m;    /* movement is relative to this mark */
  187.     long    cnt;    /* a numeric argument (ignored) */
  188. {
  189.     char    *scan;
  190.  
  191.     /* move to the first non-whitespace character */
  192.     pfetch(markline(m));
  193.     scan = ptext;
  194.     m &= ~(BLKSIZE - 1);
  195.     while (*scan == ' ' || *scan == '\t')
  196.     {
  197.         scan++;
  198.         m++;
  199.     }
  200.  
  201.     return m;
  202. }
  203.  
  204. /*ARGSUSED*/
  205. MARK    m_rear(m, cnt)
  206.     MARK    m;    /* movement is relative to this mark */
  207.     long    cnt;    /* a numeric argument (ignored) */
  208. {
  209.     /* Try to move *EXTREMELY* far to the right.  It is fervently hoped
  210.      * that other code will convert this to a more reasonable MARK before
  211.      * anything tries to actually use it.  (See adjmove() in vi.c)
  212.      */
  213.     return m | (BLKSIZE - 1);
  214. }
  215.  
  216. #ifndef NO_SENTENCE
  217. static int isperiod(ptr)
  218.     char    *ptr;    /* pointer to possible sentence-ender */
  219. {
  220.     /* if not '.', '?', or '!', then it isn't a sentence ender */
  221.     if (*ptr != '.' && *ptr != '?' && *ptr != '!')
  222.     {
  223.         return FALSE;
  224.     }
  225.  
  226.     /* skip any intervening ')', ']', or '"' characters */
  227.     do
  228.     {
  229.         ptr++;
  230.     } while (*ptr == ')' || *ptr == ']' || *ptr == '"');
  231.  
  232.     /* do we have two spaces or EOL? */
  233.     if (!*ptr || ptr[0] == ' ' && ptr[1] == ' ')
  234.     {
  235.         return TRUE;
  236.     }
  237.     return FALSE;
  238. }
  239.  
  240. /*ARGSUSED*/
  241. MARK    m_sentence(m, cnt, cmd)
  242.     MARK    m;    /* movement is relative to this mark */
  243.     long    cnt;    /* a numeric argument */
  244.     int    cmd;    /* either '(' or ')' */
  245. {
  246.     REG char    *text;
  247.     REG long    l;
  248. #ifndef CRUNCH
  249.     /* figure out where the paragraph boundary is */
  250.     MARK        pp = m_paragraph(m, 1L, cmd=='(' ? '{' : '}');
  251. #endif
  252.  
  253.     DEFAULT(1);
  254.  
  255.     /* If '(' command, then move back one word, so that if we hit '(' at
  256.      * the start of a sentence we don't simply stop at the end of the
  257.      * previous sentence and bounce back to the start of this one again.
  258.      */
  259.     if (cmd == '(')
  260.     {
  261.         m = m_bword(m, 1L, 'b');
  262.         if (!m)
  263.         {
  264.             return m;
  265.         }
  266.     }
  267.  
  268.     /* get the current line */
  269.     l = markline(m);
  270.     pfetch(l);
  271.     text = ptext + markidx(m);
  272.  
  273.     /* for each requested sentence... */
  274.     while (cnt-- > 0)
  275.     {
  276.         /* search forward for one of [.?!] followed by spaces or EOL */
  277.         do
  278.         {
  279.             if (cmd == ')')
  280.             {
  281.                 /* move forward, wrap at end of line */
  282.                 if (!text[0])
  283.                 {
  284.                     if (l == nlines)
  285.                     {
  286.                         goto BreakBreak;
  287.                     }
  288.                     l++;
  289.                     pfetch(l);
  290.                     text = ptext;
  291.                 }
  292.                 else
  293.                 {
  294.                     text++;
  295.                 }
  296.             }
  297.             else
  298.             {
  299.                 /* move backward, wrap at beginning of line */
  300.                 if (text == ptext)
  301.                 {
  302.                     do
  303.                     {
  304.                         if (l == 1L)
  305.                         {
  306.                             goto BreakBreak;
  307.                         }
  308.                         l--;
  309.                         pfetch(l);
  310.                     } while (!*ptext);
  311.                     text = ptext + plen - 1;
  312.                 }
  313.                 else
  314.                 {
  315.                     text--;
  316.                 }
  317.             }
  318.         } while (!isperiod(text));
  319.     }
  320. BreakBreak:
  321.  
  322.     /* construct a mark for this location */
  323.     m = buildmark(text);
  324.  
  325.     /* move forward to the first word of the next sentence */
  326.     m = m_fword(m, 1L, 'w', '\0');
  327.     if (m == MARK_UNSET)
  328.     {
  329.         m = MARK_EOF;
  330.     }
  331.  
  332. #ifndef CRUNCH
  333.     /* don't cross the paragraph boundary */
  334.     if (pp && ((cmd=='(') ? (m<pp) : (m>pp)))
  335.     {
  336.         m = pp;
  337.     }
  338. #endif
  339.  
  340.     return m;
  341. }
  342. #endif
  343.  
  344. MARK    m_paragraph(m, cnt, cmd)
  345.     MARK    m;    /* movement is relative to this mark */
  346.     long    cnt;    /* a numeric argument */
  347.     int    cmd;    /* either '{' or '}' */
  348. {
  349.     char    *text;    /* text of the current line */
  350.     char    *pscn;    /* used to scan thru value of "paragraphs" option */
  351.     long    l, ol;    /* current line number, original line number */
  352.     int    dir;    /* -1 if we're moving up, or 1 if down */
  353.     char    col0;    /* character to expect in column 0 */
  354.     long    limit;    /* line where searching must stop */
  355. #ifndef NO_SENTENCE
  356. # define SENTENCE(x)    (x)
  357.     char    *list;    /* either o_sections or o_paragraph */
  358. #else
  359. # define SENTENCE(x)
  360. #endif
  361. #ifndef CRUNCH
  362.     MARK    ss;
  363. #endif
  364.  
  365.     DEFAULT(1);
  366.  
  367.     /* set the direction, based on the command */
  368.     switch (cmd)
  369.     {
  370.       case '{':
  371.         dir = -1;
  372.         col0 = '\0';
  373.         SENTENCE(list = o_paragraphs); 
  374. #ifndef CRUNCH
  375.         ss = m_paragraph(m, 1L, '<');
  376.         if (ss)
  377.             limit = markline(ss);
  378.         else
  379. #endif
  380.             limit = 1L;
  381.         break;
  382.  
  383.       case '}':
  384.         dir = 1;
  385.         col0 = '\0';
  386.         SENTENCE(list = o_paragraphs); 
  387. #ifndef CRUNCH
  388.         ss = m_paragraph(m, 1L, '>');
  389.         if (ss)
  390.             limit = markline(ss);
  391.         else
  392. #endif
  393.             limit = nlines;
  394.         break;
  395.  
  396.       case '[':
  397.         if (getkey(0) != '[')
  398.         {
  399.             return MARK_UNSET;
  400.         }
  401.         /* fall through... */
  402.       case '<':
  403.         dir = -1;
  404.         col0 = '{';
  405.         SENTENCE(list = o_sections); 
  406.         limit = 1L;
  407.         break;
  408.  
  409.       case ']':
  410.         if (getkey(0) != ']')
  411.         {
  412.             return MARK_UNSET;
  413.         }
  414.         /* fall through... */
  415.       case '>':
  416.         dir = 1;
  417.         col0 = '{';
  418.         SENTENCE(list = o_sections); 
  419.         limit = nlines;
  420.         break;
  421.     }
  422.     ol = l = markline(m);
  423.  
  424.     /* for each paragraph that we want to travel through... */
  425.     while (l != limit && cnt-- > 0)
  426.     {
  427.         /* skip blank lines between paragraphs */
  428.         while (l != limit && col0 == *(text = fetchline(l)))
  429.         {
  430.             l += dir;
  431.         }
  432.  
  433.         /* skip non-blank lines that aren't paragraph separators
  434.          */
  435.         do
  436.         {
  437. #ifndef NO_SENTENCE
  438.             if (*text == '.' && l != ol)
  439.             {
  440.                 for (pscn = list; pscn[0] && pscn[1]; pscn += 2)
  441.                 {
  442.                     if (pscn[0] == text[1] && pscn[1] == text[2])
  443.                     {
  444.                         pscn = (char *)0;
  445.                         goto BreakBreak;
  446.                     }
  447.                 }
  448.             }
  449. #endif
  450.             l += dir;
  451.         } while (l != limit && col0 != *(text = fetchline(l)));
  452. BreakBreak:    ;
  453.     }
  454.  
  455.     m = MARK_AT_LINE(l);
  456. #ifdef DEBUG2
  457.     debout("m_paragraph() returning %ld.%d\n", markline(m), markidx(m));
  458. #endif
  459.     return m;
  460. }
  461.  
  462.  
  463. /*ARGSUSED*/
  464. MARK    m_match(m, cnt)
  465.     MARK    m;    /* movement is relative to this mark */
  466.     long    cnt;    /* a numeric argument (normally 0) */
  467. {
  468.     long    l;
  469.     REG char    *text;
  470.     REG char    match;
  471.     REG char    nest;
  472.     REG int        count;
  473.  
  474. #ifndef NO_EXTENSIONS
  475.     /* if we're given a number, then treat it as a percentage of the file */
  476.     if (cnt > 0)
  477.     {
  478.         /* make sure it is a reasonable number */
  479.         if (cnt > 100)
  480.         {
  481.             msg("can only be from 1%% to 100%%");
  482.             return MARK_UNSET;
  483.         }
  484.  
  485.         /* return the appropriate line number */
  486.         l = (nlines - 1L) * cnt / 100L + 1L;
  487.         return MARK_AT_LINE(l);
  488.     }
  489. #endif /* undef NO_EXTENSIONS */
  490.  
  491.     /* get the current line */
  492.     l = markline(m);
  493.     pfetch(l);
  494.     text = ptext + markidx(m);
  495.  
  496.     /* search forward within line for one of "[](){}" */
  497.     for (match = '\0'; !match && *text; text++)
  498.     {
  499.         /* tricky way to recognize 'em in ASCII */
  500.         nest = *text;
  501.         if ((nest & 0xdf) == ']' || (nest & 0xdf) == '[')
  502.         {
  503.             match = nest ^ ('[' ^ ']');
  504.         }
  505.         else if ((nest & 0xfe) == '(')
  506.         {
  507.             match = nest ^ ('(' ^ ')');
  508.         }
  509.         else
  510.         {
  511.             match = 0;
  512.         }
  513.     }
  514.     if (!match)
  515.     {
  516.         return MARK_UNSET;
  517.     }
  518.     text--;
  519.  
  520.     /* search forward or backward for match */
  521.     if (match == '(' || match == '[' || match == '{')
  522.     {
  523.         /* search backward */
  524.         for (count = 1; count > 0; )
  525.         {
  526.             /* wrap at beginning of line */
  527.             if (text == ptext)
  528.             {
  529.                 do
  530.                 {
  531.                     if (l <= 1L)
  532.                     {
  533.                         return MARK_UNSET;
  534.                     }
  535.                     l--;
  536.                     pfetch(l);
  537.                 } while (!*ptext);
  538.                 text = ptext + plen - 1;
  539.             }
  540.             else
  541.             {
  542.                 text--;
  543.             }
  544.  
  545.             /* check the char */
  546.             if (*text == match)
  547.                 count--;
  548.             else if (*text == nest)
  549.                 count++;
  550.         }
  551.     }
  552.     else
  553.     {
  554.         /* search forward */
  555.         for (count = 1; count > 0; )
  556.         {
  557.             /* wrap at end of line */
  558.             if (!*text)
  559.             {
  560.                 if (l >= nlines)
  561.                 {
  562.                     return MARK_UNSET;
  563.                 }
  564.                 l++;
  565.                 pfetch(l);
  566.                 text = ptext;
  567.             }
  568.             else
  569.             {
  570.                 text++;
  571.             }
  572.  
  573.             /* check the char */
  574.             if (*text == match)
  575.                 count--;
  576.             else if (*text == nest)
  577.                 count++;
  578.         }
  579.     }
  580.  
  581.     /* construct a mark for this place */
  582.     m = buildmark(text);
  583.     return m;
  584. }
  585.  
  586. /*ARGSUSED*/
  587. MARK    m_tomark(m, cnt, key)
  588.     MARK    m;    /* movement is relative to this mark */
  589.     long    cnt;    /* (ignored) */
  590.     int    key;    /* keystroke - the mark to move to */
  591. {
  592.     /* mark '' is a special case */
  593.     if (key == '\'' || key == '`')
  594.     {
  595.         if (mark[26] == MARK_UNSET)
  596.         {
  597.             return MARK_FIRST;
  598.         }
  599.         else
  600.         {
  601.             return mark[26];
  602.         }
  603.     }
  604.  
  605.     /* if not a valid mark number, don't move */
  606.     if (key < 'a' || key > 'z')
  607.     {
  608.         return MARK_UNSET;
  609.     }
  610.  
  611.     /* return the selected mark -- may be MARK_UNSET */
  612.     if (!mark[key - 'a'])
  613.     {
  614.         msg("mark '%c is unset", key);
  615.     }
  616.     return mark[key - 'a'];
  617. }
  618.  
  619.